/*
 * EnableGateDescription.java
 * 
 * last update: 16.01.2010 by Stefan Saru
 * 
 * author:	Alec(panovici@elcom.pub.ro)
 * 
 * Obs:
 */

package engine;

import java.util.*;
import java.io.*;
import middle.*;

/**
 * enable_gate can be one of the following:
 * bufif0/bufif1/notif0/notif1
 */
class EnableGateDescription extends StdGateDescription
{

	EnableGateDescription (byte type) {
		super(type, 3);
	}

	///////////////////////////////
	// ModuleFactory implementation
	///////////////////////////////

	/*
	 * this one actally is a shamelessly made copy of NInputGateDescription
	 */
	public Object createNewModule(NameSpace parent,
			ModuleInstanceDescription miDesc,
			byte strength,
			ScopeNode scope)
	throws ParseException
	{
		xConsole.debug("creating new EnableGate");
		ExpressionDescription output;
		Enumeration e = miDesc.portsVector.elements();
		try {
			output = (ExpressionDescription) e.nextElement();
			if (output == null) {
				xConsole.debug("EnableGate not created: output is null");
				return null; //no output, so ..
			}
			try {
				((AssignableSelection)output).toContSelection(strength);
			} catch (ClassCastException cex) {
				throw new ParseException ("output expression is not" +
				" a net selection or concatenation");
			}

			SelectionExpressionDescription input = new
			SelectionExpressionDescription();

			if (e.hasMoreElements()) { //the input port
				ExpressionDescription ck = (ExpressionDescription) e.nextElement();
				input.addChunk(ck == null ? ConstantDescription.zDescription :
					ck);
			} else
				throw new ParseException("wrong number of ports");

			if (e.hasMoreElements()) {//the enable port
				ExpressionDescription ck = (ExpressionDescription) e.nextElement();
				input.addChunk(ck == null ? ConstantDescription.zDescription :
					ck);
			} else
				throw new ParseException("wrong number of ports");
			if(e.hasMoreElements())
				throw new ParseException("wrong number of ports");
			return new EnableGate (parent, delay,
					(LeftValue) output.instantiate(parent),
					input.instantiate(parent),
					miDesc, type, strength);
		} catch (ParseException pex) {
			throw new ParseException(parent.desc.toString(miDesc.lineNo) +
					": error: " + pex);
		}
	}

	/**
	 * The difference from NInputGateDescription's createNew....Array
	 * is that the intarmediary structure for bundling outputs is a
	 * Wire.
	 */
	public Object createNewModuleArray(NameSpace parent,
			ModuleInstanceDescription miDesc,
			byte strength,
			ScopeNode scope, int ars, int are,
			int n, int increment)
	throws ParseException
	{
		Enumeration en = miDesc.portsVector.elements();
		ExpressionDescription output = (ExpressionDescription) en.nextElement();
		if (output == null) return null; //no output, so ..

		EnableGate gates[] = new EnableGate[n];
		Vector[] inputs  = new Vector[n]; //the input chunks
		for (int i = 0; i < n; i++)
			inputs[i] = new Vector();
		LeftValue[] outputs = new LeftValue[n];
		Monitor m;
		try {    
			try {
				((AssignableSelection) output).toContSelection(strength);
			} catch (ClassCastException cex) {
				throw new ParseException("bad output port expression: not a net");
			}

			LeftValue[] o = new LeftValue[1];
			try {
				o[0] = (LeftValue) output.instantiate(parent);
			} catch (ClassCastException cex) {
				throw new ParseException ("bad output port expression: not a lValue");
			}

			if (((Expression) o[0]).length != 1) {
				if (((Expression) o[0]).length != n)
					throw new ParseException ("bad output port length");


				Wire buffer = new Wire (null, null, Assignable.typeWire,
						o[0].length()-1, 0,
						WireDescription.defaultExpandType,
						Delay3.nullDelay());
				for (int i = n-1; i >= 0 ; i--)
					outputs[i] = new ContBitSelect(parent, buffer, null, i, i);

				Expression[] dummy = {new BitSelect(parent, buffer, null, n-1, 0)};
				m = new MContAssignMonitor(o, dummy); 
			} else {
				outputs[0] = o[0];
				for (int i = 1; i < n; i++)
					outputs[i] = (LeftValue) output.instantiate(parent);
			}

			while (en.hasMoreElements()) { //the inputs
				ExpressionDescription ed =
					(ExpressionDescription) en.nextElement();
				Expression e =
					ed == null ? ConstantDescription.zDescription.instantiate(parent) :
						ed.instantiate(parent);

					if (e.length != 1) {
						if (e.length != n)
							throw new ParseException("bad input port expression" +
									" length for \"" + ed + "\"");
						BitVector buffer = new BitVector (e.length-1, 0, false);
						m = new LinkMonitor(new BitSelect(parent, buffer,
								null, n-1, 0),
								e);
						for (int i = n-1; i >= 0; i--)
							inputs[i].addElement(new BitSelect(parent, buffer, null, i, i));
					} else
						for (int i = 0; i < n; i++)
							inputs[i].addElement(e);
			}

			for (int i = 0; i < n; i++) {
				gates[i] = new EnableGate(parent, delay, outputs[i],
						new SelectionExpression (parent,
								inputs[i],
								-8778),
								miDesc, type, strength);
			}

			return gates;
		} catch (ParseException pex) {
			throw new ParseException(parent.desc.toString(miDesc.lineNo) +
					": error: " + pex);
		}
	}

}







